"""
Context基类用于在主线程执行异步的数据生成器或者装饰器
比如Websocket/Tcp/Udp等执行tx以及rx的服务
主协程实现`run_main`，并在其中调用`tx`和`rx`方法形成数据的双向流动
`rx`部分异步等待TraceWrapper的Future部分, 实现符合顺序的收发
"""
from __future__ import annotations
from .stream import TraceStream, TraceWrapper
from abc import ABC, abstractmethod
from typing import AsyncGenerator, Any
import asyncio
import traceback

class BaseContext(ABC, TraceStream):
    def __init__(self, generator: AsyncGenerator, **kwargs):
        self.generator = generator
        self._is_working = False
        super().__init__(**kwargs)

    def __call__(self, data:Any) -> Any:
        """
        Context不直接处理数据, 直接输入None, 传递Any
        """

    async def run_porter(self, bg_loop):
        # Context不跑Porter线程
        return

    async def run_main(self, loop: asyncio.AbstractEventLoop):
        if self._is_working:
            self.logger.warning("Context is already running in other pipeline, skipping in this one")
            return
        self._running_count = 1
        self.loop_main = loop
        self._is_working = True
        self._start_event.set()
        try:
            async with asyncio.TaskGroup() as tg:
                tg.create_task(self.tx_loop())
                tg.create_task(self.rx_loop())
        except BaseExceptionGroup as eg:
            for e in eg.exceptions:
                self.logger.error(f"{''.join(traceback.format_exception(e))}")
        except Exception as e:
            self.logger.error(f"unexpected exception: {e}")
        finally:
            await self.export(TraceWrapper(None)) # 发送终止信号
        while True:
            if self._buffer.__len__() == 0:
                break
            await asyncio.sleep(0.1)
        self._is_working = False
        self._start_event.clear()

    @abstractmethod
    async def rx_loop(self):
        # 需要持续调用 self.export(TraceWrapper(...)), 并将id记录保存下来供tx使用
        # 根据业务需求决定RX/TX的交互方式, 整体通过Wrapper的Future来转移
        pass

    @abstractmethod
    async def tx_loop(self):
        # 根据id记录顺序拉取self.traced_data, await TraceWrapper内的Future
        # 需要无序的话使用asyncio.wait
        pass